package com.ruoyi.web.controller.common;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ruoyi.meterManager.mapper.MeterreadMapper;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.framework.config.ServerConfig;

import java.io.*;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 通用请求处理
 * 
 * @author ruoyi
 */
@RestController
public class CommonController
{
    private static final Logger log = LoggerFactory.getLogger(CommonController.class);

    @Autowired
    private ServerConfig serverConfig;
    @Autowired
    private MeterreadMapper meterreadMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 通用下载请求
     * 
     * @param fileName 文件名称
     * @param delete 是否删除
     */
    @GetMapping("common/download")
    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
    {
        try
        {
            if (!FileUtils.checkAllowDownload(fileName))
            {
                throw new Exception(StringUtils.format("文件名称({})非法，不允许下载。 ", fileName));
            }
            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
            String filePath = RuoYiConfig.getDownloadPath() + fileName;

            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, realFileName);
            FileUtils.writeBytes(filePath, response.getOutputStream());
            if (delete)
            {
                FileUtils.deleteFile(filePath);
            }
        }
        catch (Exception e)
        {
            log.error("下载文件失败", e);
        }
    }

    /**
     * 通用上传请求
     */
    @PostMapping("/common/upload")
    public AjaxResult uploadFile(MultipartFile file) throws Exception
    {
        try
        {
            // 上传文件路径 E:/凯纳科技/抄表APP/uploadPath/upload
            String filePath = RuoYiConfig.getUploadPath();
            // 上传并返回新文件名称 /profile/upload/2021/08/03/a7e196c0-1c17-42cd-98d3-ba4582adf7bd.JPG
            String fileName = FileUploadUtils.upload(filePath, file);
            // http://localhost:8090/profile/upload/2021/08/03/a7e196c0-1c17-42cd-98d3-ba4582adf7bd.JPG
            String url = serverConfig.getUrl() + fileName;
            AjaxResult ajax = AjaxResult.success();
            ajax.put("fileName", fileName);
            ajax.put("url", url);
            return ajax;
        }
        catch (Exception e)
        {
            return AjaxResult.error(e.getMessage());
        }
    }


    /**
     * 通用上传请求
     */
    @PostMapping("/common/upload/test")
    public AjaxResult uploadFileTest(MultipartFile file) throws Exception
    {
        try
        {

            Map<String,String> printInfo = new HashMap<>();
            printInfo.put("OANAME","oaname");
            printInfo.put("MIID","miid");
            printInfo.put("MISEQNO","miseqno");
            printInfo.put("MINAME","miname");
            printInfo.put("MISMFID","mismfid123");
            String filePath = RuoYiConfig.getUploadPath() + printInfo.get("MISMFID");
            String pmpath = FileUploadUtils.uploadMeterImg(filePath,file,printInfo,1);
            // 上传文件路径 E:/凯纳科技/抄表APP/uploadPath/upload

            AjaxResult ajax = AjaxResult.success();
            return ajax;
        }
        catch (Exception e)
        {
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 本地资源通用下载
     */
    @GetMapping("/common/download/resource")
    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
            throws Exception
    {
        try
        {
            if (!FileUtils.checkAllowDownload(resource))
            {
                throw new Exception(StringUtils.format("资源文件({})非法，不允许下载。 ", resource));
            }
            // 本地资源路径
            String localPath = RuoYiConfig.getProfile();
            // 数据库资源地址
            String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
            // 下载名称
            String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, downloadName);
            FileUtils.writeBytes(downloadPath, response.getOutputStream());
        }
        catch (Exception e)
        {
            log.error("下载文件失败", e);
        }
    }

    /**
     * @方法名称 getUpdatePath
     * @功能描述 获取下载链接
     * @作者信息 Chen_henan
     * @创建时间 2021-10-12
     * @返回类型 java.util.Map
     */
    @PostMapping("/common/getUpdatePath")
    public @ResponseBody
    Map getUpdatePath(HttpServletRequest request) {
        int status = HttpStatus.INTERNAL_SERVER_ERROR.value();
        Map map = new LinkedHashMap();
        try {
            //获取下载地址
            String path = "apkDownload";
            // 获取文件
            File f = new File(path);
            if (!f.exists()) {//判断文件或目录是否存在
                status = HttpStatus.PRECONDITION_REQUIRED.value();
                map.put("data", new HashMap());
                map.put("state", new AjaxResult(status, "文件或目录不存在!"));
                return map;
            }
            if (f.isDirectory() && f.list().length <= 0) {
                status = HttpStatus.PRECONDITION_REQUIRED.value();
                map.put("data", new HashMap());
                map.put("state", new AjaxResult(status, "无可用更新文件!"));
                return map;
            }
            String name = null;
            // 获取目录下的文件及路径
            File fa[] = f.listFiles();
            Double version = 0.0;
            for (File fi : fa) {
                log.info(fi.getName() + "  " + fi.getPath());
                name = fi.getName();//得到文件名
                // 获取到版本号 cbqd-v1.8.apk
                String fileVersions = name.substring(name.lastIndexOf("-") + 2, name.lastIndexOf("."));
                // 比对版本 取最大的
                if (Double.parseDouble(fileVersions) > version) {
                    version = Double.parseDouble(fileVersions);
                }
            }

            String version_describe = "";
            String key = "version_describe_" + version;
            //version_describe = meterreadMapper.getUpdateInfo(version+"");
            version_describe = (String)redisTemplate.opsForValue().get(key);
            if(StringUtils.isBlank(version_describe)) {
                version_describe = meterreadMapper.getUpdateInfo(version+"");
                redisTemplate.opsForValue().set(key,version_describe);
            }
            String ipAddr = getIpAddr(request);
            log.info("访问ip：" + ipAddr);
            System.out.println(ipAddr);

            status = HttpStatus.OK.value();
            map.put("versions", version);
            map.put("describe", version_describe);
            map.put("updateIp", request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/common/updateApk?apkName=" + name.substring(0, name.lastIndexOf("v") + 1) + version + name.substring(name.lastIndexOf(".")));
            map.put("state", new AjaxResult(status, "success"));
        } catch (Exception e) {
            e.printStackTrace();
            map.put("error", e.getMessage());
        } finally {
            return map;
        }
    }


    /**
     * @方法名称 updateApk
     * @功能描述 下载更新包
     * @作者信息 Chen_henan
     * @创建时间 2021-10-12
     * @返回类型 java.util.Map
     */
    @GetMapping(value = "/common/updateApk", produces = "application/json;charset=UTF-8")
    public Map updateApk(HttpServletResponse response, HttpServletRequest request, String apkName) {
        Map map = new LinkedHashMap();
        int status = HttpStatus.INTERNAL_SERVER_ERROR.value();
        if (StringUtils.isEmpty(apkName)) {
            status = HttpStatus.PRECONDITION_REQUIRED.value();
            map.put("data", new HashMap());
            map.put("state", new AjaxResult(status, "更新包名称不能为空!"));
            return map;
        }
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            //获取下载地址
            String path = "apkDownload" + File.separator + apkName;

            // 以流的形式下载文件
            inputStream = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[inputStream.available()];//在内存中开辟块缓冲区  buffer有利于较少内存碎片 inputStream.available() 得到文件字节长度
            inputStream.read(buffer);
            inputStream.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.setHeader("content-type", "application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + new String(apkName.getBytes()));
            response.addHeader("Content-Length", "" + new File(path).length());
            outputStream = new BufferedOutputStream(response.getOutputStream());//BufferedOutputStream 字节缓冲输出流
            outputStream.write(buffer);
            if (inputStream != null) {
                inputStream.close();//关闭输入流
            }
            if (outputStream != null) {
                outputStream.flush();//刷新此缓冲的输出流。这迫使所有缓冲的输出字节被写出到底层输出流中。
                outputStream.close();//关闭此输出流并释放与此流有关的所有系统资源。
            }
        } catch (IOException ex) {
            ex.printStackTrace();
            map.put("state", new AjaxResult(status, ex.getMessage()));
            return map;
        }
        return null;
    }


    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            if(ip.contains("../")||ip.contains("..\\")){
                return "";
            }
            return ip;
        }
        ip = request.getHeader("X-Forwarded-For");
        if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个IP值，第一个为真实IP。
            int index = ip.indexOf(',');
            if (index != -1) {
                ip= ip.substring(0, index);
            }
            if(ip.contains("../")||ip.contains("..\\")){
                return "";
            }
            return ip;
        } else {
            ip=request.getRemoteAddr();
            if(ip.contains("../")||ip.contains("..\\")){
                return "";
            }
            if(ip.equals("0:0:0:0:0:0:0:1")){
                ip="127.0.0.1";
            }
            return ip;
        }

    }
}
